try (closeRolloutFloater tansferDataFromLevelSeqFloater) catch()
rollout rolloutRampGenerator "Level Sequence 数据传递工具"
(   
    local uiDataSectionName = "Cutscene Data Transform Tool"

    fn aurogonConfigDir = 
    (
        return (getFilenamePath (getDir #archives) + "AurogonConfig") -- "C:/Users/<username>/Documents/3dsMax/AurogonConfig"
    )

    fn aurogonConfigUiIni = 
    (   
        configDir = aurogonConfigDir()
        uiData = configDir + "/toolUiData.ini"
        return uiData
    )
    
    fn recordUIData key_string value_string = 
    (
        iniFile = aurogonConfigUiIni()
        setINISetting iniFile uiDataSectionName key_string value_string
    )

    fn loadUiData key_string = 
    (
        iniFile = aurogonConfigUiIni()
        return (getINISetting iniFile uiDataSectionName key_string)
    )
    
    fn initScene =
    (
        resetMaxFile #noPrompt
        frameRate = 60
        -- preferences.spinnerPrecision = 3
    )

    -- import fbx with animation
    fn importFbxWithAnim fbxWithAnimPath =
    (	
        FBXImporterSetParam "Mode" #create
        FBXImporterSetParam "Animation" True
        if fbxWithAnimPath.count > 0 then (importFile fbxWithAnimPath #noPrompt using:FbxImporter)
    )

    fn getDataFromXml dataFilePath =
    (
        xmlDoc = dotNetObject "System.Xml.XmlDocument"
        xmlDoc.load dataFilePath
        
        data = #()
        docElement = xmlDoc.documentElement
        rootElement = docElement.childNodes
        for i = 0 to (rootElement.count - 1) do
        (
            objectName = rootElement.itemOf[i].name
            startFrame = rootElement.itemOf[i].innerText as integer
            append data #(objectName, startFrame)
        )

        return data
    )

    fn getRoot node = if isvalidnode node do 
    (
        while node.parent != undefined do node = node.parent
        return node
    )

    fn transferData fbxFromLevelSeq maxAnimFilePaths = 
    (   
        -- fbxFromLevelSeq = "D:\Temp\ueToDccTest\cs_pv2_shot14b\cam_anim.fbx"
        -- maxAnimFilePaths = #("D:\Temp\ueToDccTest\cs_pv2_shot14b\cs_pv02_03.max", "D:\Temp\ueToDccTest\cs_pv2_shot14b\cs_pv02_01.max")
        
        initScene()
        importFbxWithAnim fbxFromLevelSeq

        objAnimData = getDataFromXml ((FilterString fbxFromLevelSeq ".")[1] + ".xml")
        objectNodesFromLevelSeq = #()

        for i = 1 to objAnimData.count do
        (
            objName = objAnimData[i][1]
            startFrame = objAnimData[i][2]
            objNode = getNodeByName objName
            append objectNodesFromLevelSeq objNode

            -- add custom attr "startFrame"
            startFrameAttr = attributes weaponData
            (
                parameters main rollout:params (startFrame type:#float ui:sFrame default:0)
                rollout params "Level Sequence Parameters" (spinner sFrame "Start Frame" type: #float)
            )
            
            custAttributes.add objNode startFrameAttr
            objNode.startFrame = startFrame
            
            if superClassOf obj == camera then continue
        )

        select objectNodesFromLevelSeq
        max select invert
        delete $

        -- load animation file and check Root count
        animFileNames = #()
        for maxAnimFilePath in maxAnimFilePaths do
        (
            fileName = getFilenameFile maxAnimFilePath
            append animFileNames fileName
        )
        
        for maxAnimFilePath in maxAnimFilePaths do
        (
            mergeMAXFile maxAnimFilePath #noRedraw #mergeDups #select-- quiet:True

            -- remove cameras in animation file
            abandonCameras = #()
            for node in $ do (if superClassOf node == camera then append abandonCameras node)
            delete abandonCameras

            characterNameObj = ""
            rootNodes = rootnode.children
            for node in rootNodes do
            (
                if classOf node == SplineShape do
                (
                    characterNameObj = node
                    break
                )
            )
            if characterNameObj == "" then
                return messageBox("找不到角色基础片!\t")

            rootNodeWithoutParent = #()
            for obj in $*Root* do
            (
                if obj.parent == undefined then (append rootNodeWithoutParent obj)
            )

            select rootNodeWithoutParent
            startFrame = 0
            for item in objectNodesFromLevelSeq do
            (
                if superClassOf item == camera then
                    continue

                if (findString item.name characterNameObj.name != undefined) then 
                (
                    $.parent = item
                    in coordsys parent $.rotation = (quat 0 0 -0.707107 -0.707107)  -- If set pos first, the pos will not be set sucessfully, I don't know why.
                    in coordsys parent $.pos = [0,-10,0]
                    index = findItem objectNodesFromLevelSeq item
                    deleteItem objectNodesFromLevelSeq index 
                    startFrame = item.startFrame
                    break
                )
            )

            -- offset frame under Root
            macros.run "Scene Explorer" "SESelectChildren"
            for item in $ do (moveKeys item.controller startFrame)

            clearSelection()
            nodeNeedToReparent = #()
            for node in rootNodes do
            (
                if (findItem animFileNames node.name) == 0 and (findItem objectNodesFromLevelSeq node) == 0 then
                (
                    append nodeNeedToReparent node
                )
            )

            -- use anim file name as dummy name
            fileName = getFilenameFile maxAnimFilePath
            newDummy = Dummy name:fileName
            for node in nodeNeedToReparent do (node.parent = newDummy)
        )

        -- view in camera
		if viewport.numViews > 1 do (max tool maximize)
        viewport.setcamera cameras[1]

        clearSelection()
        saveMaxFile ((FilterString fbxFromLevelSeq ".")[1] + "_transData" + ".max") clearNeedSaveFlag:True useNewFile:True
    )

    fn getMultiOpenFileName caption types =
	(
		theDialog = dotNetObject "System.Windows.Forms.OpenFileDialog" --create a OpenFileDialog
		theDialog.title = caption --set the title
		theDialog.Multiselect = true --allow multiple files to be selected
		theDialog.Filter = types --specify the filter like "HTML Files (*.html)|*.html|All Files (*.*)|*.*"
		-- theDialog.FilterIndex = 2 --set the filter drop-down list to All Files
		result = theDialog.showDialog() --display the dialog, get result into variable
		result.ToString() --when closed, convert the result to string
		result.Equals result.OK --returns TRUE if Open was pressed, FALSE otherwise
		result.Equals result.Cancel --returns TRUE if Cancel was pressed, FALSE otherwise
		theFilenames = theDialog.fileNames --the selected filenames will be returned as an array
		return theFilenames
	)

    -- edittext startFrameEditText "起始帧:" fieldWidth:40 text:"0" align:#center
    group ""
    (
        edittext fbxFromLevelSeqEditText "角色、相机 fbx 路径:" text: (loadUiData "fbxFromLevelSeqEditText")
        button fbxFromLevelSeqButton "添加路径" toolTip:"从UE Level Sequence导出的 fbx 路径（包含相机和角色动画）"    
        -- edittext animMaxFileEditText "max 动画文件路径:"
        -- button animMaxFileButton "添加路径" toolTip:"原始max动画文件"
		multiListBox animFileList "max 动画文件路径:" height:7 items:(FilterString (loadUiData "animFilePaths") ";") readOnly:false
		button addAnimFileButton "添加 max 动画文件路径" toolTip:"原始max动画文件，将路径添加到上面的列表中" align:#center across:2
		button deleteAnimFileButton "删除 max 动画文件路径" toolTip:"删除上面的列表中选择的路径" align:#center
    )
    button transferDataButton "开始数据传递" toolTip:"将动画文件与 UE Level Sequence 镜头位置校准"

	on fbxFromLevelSeqButton pressed do
	(	
		filePath = getOpenFileName \
		caption:"选择UE Level Seuquence 导出的 fbx" \
		types:"Fbx(*.fbx)|*.fbx"
		if filePath != undefined then fbxFromLevelSeqEditText.text = filePath
        recordUIData "fbxFromLevelSeqEditText" filepath
	)

	on addAnimFileButton pressed do
	(	
		caption = "选择 max 动画文件"
		types = "3ds Max(*.max)|*.max"
		filePaths = getMultiOpenFileName caption types

        recordStr = ""
		if filePaths != #() then
		(
			tempArray = animFileList.items
			for path in filePaths do
			(	
				if (findItem tempArray path) != 0 do continue
				animFileList.items = append animFileList.items path
                recordStr += path
                recordStr += ";"
			)
		)
        recordUIData "animFilePaths" recordStr
	)

	on deleteAnimFileButton pressed do
	(	
		animFileList.items = for i = 1 to animFileList.items.count where not animFileList.selection[i] collect animFileList.items[i]
		animFileList.selection = #{}
        recordUIData "animFilePaths" (animFileList.items as string)
	)

	on transferDataButton pressed do
	(	
        fbxFromLevelSeq = fbxFromLevelSeqEditText.text
        maxAnimFilePaths = animFileList.items
        transferData fbxFromLevelSeq maxAnimFilePaths
    )
)

tansferDataFromLevelSeqFloater = newrolloutfloater "Level Sequence 数据传递工具" 400 280
addrollout rolloutRampGenerator tansferDataFromLevelSeqFloater
